`timescale 1ns/1ps
`default_nettype none

/* NOTE:
* - 扫描译码
*/

module cxy_scan_decoder (
    // system signal
    input  wire         I_sclk,  // 125M
    input  wire         I_rst_n,
    // config
    input  wire [5:0]   I_cfg_scan_max,         // 最大扫描id
    input  wire [3:0]   I_cfg_decode_type,      // 译码方式
    input  wire [15:0]  I_cfg_decode_param0,    // 译码参数0
    input  wire [15:0]  I_cfg_decode_param1,    // 译码参数1
    input  wire [15:0]  I_cfg_decode_param2,    // 译码参数2,for 2018

    input  wire [7:0]   I_cfg_rck_num,          //一行rck的个数
    input  wire [15:0]  I_cfg_rck_len,          //每个rck的长度

    input  wire [15:0]  I_cfg_deghost_ctrl_dly, // 消影信号延迟
    input  wire [15:0]  I_cfg_deghost_ctrl_len, // 消影信号长度

    // control
    input  wire         I_scan_prep,            // 准备换行
    input  wire [5:0]   I_scan_num,             // 行id
    input  wire         I_scan_commit,          // 执行换行

    input  wire         I_display_end,          //每个显示周期结束标识
    // scan out
    output wire         O_deghost_ctrl,
    output wire [4:0]   O_scan_out
    );
//------------------------Parameter----------------------
localparam [3:0]
    MODE_138  = 0, // 138译码
    MODE_LOW  = 1, // 直接输出（低）
    MODE_HIGH = 2, // 直接输出（高）
    MODE_595  = 3, // 595译码
    MODE_5958 = 4, // 5958译码
    MODE_5266 = 5, // SM5266P
    MODE_2018 = 6, // ICND2018
    MODE_2013 = 7, // ICND2013
    MODE_5366 = 8; // SM5366P

//------------------------Local signal-------------------
wire [9:0]  cfg_decode_param0;
wire [9:0]  cfg_decode_param1;
wire [9:0]  cfg_decode_param2;

reg  [5:0]  scan_result;
reg  [5:0]  scan_result_5266;
reg  [5:0]  scan_out;
reg  [5:0]  scan_out_buff;

reg  [9:0]  commit_cnt;
reg         commit_flag;
reg         prep_flag;

reg         clk_595;
reg         dat_595;

reg         clk_5958;
reg         dat_5958;
reg         oe_5958;

reg         bk_5266;    // c
reg         din_5266;   // b
reg         dck_5266;   // a
reg         d_5266;
reg         e_5266;
reg         pad_flag_5266;
reg  [6:0]  pad_cnt_5266;
wire [9:0]  pad_param0;
wire [9:0]  pad_param1;
wire [9:0]  pad_param2;

reg         dck_2018;
reg         dat_2018;
reg         rck_2018;
reg         rck_out_en;
reg  [4:0]  rck_cnt;
reg  [9:0]  rck_len_cnt;

reg         dly_en;
reg         ctrl_en;
reg  [9:0]  dly_cnt;
reg  [9:0]  ctrl_cnt;

//icn2013
reg          A_2013;
reg          B_2013;
reg          reg_flag_2013; //ICN2013寄存器配置标志
reg          clk_en_2013; //ICN2013寄存器时钟标志
reg  [9:0]   cnt_2013;
reg  [2:0]   clk_len_cnt_2013;
wire [9:0]   clk_num_2013;

//SM5366P
reg         BK_5366;
reg         DIN_5366;
reg         CLK_5366;
reg         reg_flag_5366; //sm5366p寄存器配置标志
reg         clk_en_5366;   //clk 时钟使能
reg         data_en_5366;  //data使能
reg  [5:0]  data_5366;     //sm5366p 寄存器值
reg  [3:0]  cyc_cnt_5366;
reg  [7:0]  num_cnt_5366;
wire  [7:0]  clk_num_5366;//clk时钟个数
reg  [9:0]  prep_cnt;

//------------------------Instantiation------------------

//------------------------Body---------------------------
assign cfg_decode_param0 = I_cfg_decode_param0[9:0];
assign cfg_decode_param1 = I_cfg_decode_param1[9:0];
assign cfg_decode_param2 = I_cfg_decode_param2[9:0];

assign O_scan_out = scan_out_buff;

//scan_result[5:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_result <= 'b0;
    else if(I_scan_prep)
    case(I_cfg_decode_type)
        MODE_LOW:   scan_result <= ~(5'b1 << I_scan_num[2:0]);
        MODE_HIGH:  scan_result <=   5'b1 << I_scan_num[2:0];
        default:    scan_result <= I_scan_num;
    endcase

//scan_result_5266[5:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_result_5266 <= 'b0;
    else if(prep_flag && commit_flag)
        scan_result_5266 <= I_scan_num ;

//commit_flag
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        commit_flag <= 'b0;
    else if(commit_cnt >cfg_decode_param0)
        commit_flag <= 1'b1;
    else 
        commit_flag <= 'b0;
       
//prep_flag
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        prep_flag <= 'b0;
    else if(I_scan_prep)
        prep_flag <= 1'b1;
    else if(commit_flag)
        prep_flag <= 'b0;

//scan_out[4:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_out <= 'b0;
    else
    case(I_cfg_decode_type)
        MODE_595:   scan_out <= {dat_595, clk_595};
        MODE_5958:  scan_out <= {dat_5958, oe_5958, clk_5958};
        MODE_5266:  scan_out <= {e_5266, d_5266, bk_5266, din_5266, dck_5266};
        MODE_5366:  if(I_scan_prep)  scan_out <= scan_result;
        MODE_2018:  scan_out <= {dat_2018,rck_2018,dck_2018};

        default:
            if(I_scan_commit)
                scan_out <= scan_result[4:0];
    endcase

always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        scan_out_buff <= 'b0;
    else
    case(I_cfg_decode_type)
        MODE_2013:  scan_out_buff <= reg_flag_2013 ? {3'd0,B_2013,A_2013} : scan_out;
        MODE_5366:  scan_out_buff <= {2'd0,DIN_5366,BK_5366,CLK_5366};
        default:    scan_out_buff <= scan_out;  //yuan
        //default:    scan_out_buff <= {2'd0,BK_5366,DIN_5366,CLK_5366};  //scan_out_buff <= scan_out;
    endcase

//commit_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        commit_cnt <= 10'd1023;
    else if(I_scan_commit)
        commit_cnt <= 10'd1;
    else if(commit_cnt<1023)
        commit_cnt <= commit_cnt + 1'b1;

//clk_595
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        clk_595 <= 'b0;
    else if(commit_cnt==cfg_decode_param0)
        clk_595 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        clk_595 <= 'b0;

//dat_595
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dat_595 <= 1'b1;
    else if(I_scan_commit)
    begin
        if(scan_result==I_cfg_scan_max)
            dat_595 <= 'b0;
        else
            dat_595 <= 1'b1;
    end

//clk_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        clk_5958 <= 'b0;
    else if(commit_cnt==cfg_decode_param0)
        clk_5958 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        clk_5958 <= 'b0;

//dat_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dat_5958 <= 'b0;
    else if(I_scan_commit)
    begin
        if(scan_result==0)
            dat_5958 <= 1'b1;
        else
            dat_5958 <= 'b0;
    end

//oe_5958
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        oe_5958 <= 1'b1;
    else if(I_scan_commit)
        oe_5958 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        oe_5958 <= 'b0;

//dck_2018
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dck_2018 <= 1'b0;
    else if(commit_cnt==cfg_decode_param0)
        dck_2018 <= 1'b1;
    else if(commit_cnt==cfg_decode_param1)
        dck_2018 <= 1'b0;

//dat_2018
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dat_2018 <= 'b0;
    else if(I_scan_commit)
    begin
        if(scan_result==0)
            dat_2018 <= 1'b1;
        else
            dat_2018 <= 1'b0;
    end

//rck_out_en
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        rck_out_en <= 1'b0;
    else if(commit_cnt==cfg_decode_param2)
        rck_out_en <= 1'b1;
    else if(rck_cnt==I_cfg_rck_num && rck_len_cnt==I_cfg_rck_len)
        rck_out_en <= 1'b0;

//rck_cnt
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        rck_cnt <= 1'b1;
    else if(!rck_out_en)
        rck_cnt <= 1'b1;
    else if(rck_len_cnt==I_cfg_rck_len)
        rck_cnt <= rck_cnt + 1'b1;

//rck_len_cnt
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        rck_len_cnt <= 1'b1;
    else if(!rck_out_en)
        rck_len_cnt <= 1'b1;
    else if(rck_len_cnt<I_cfg_rck_len)
        rck_len_cnt <= rck_len_cnt + 1'b1;
    else
        rck_len_cnt <= 1'b1;

//rck_2018
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        rck_2018 <= 1'b0;
    else if(!rck_out_en)
        rck_2018 <= 1'b0;
    else if(rck_len_cnt==1'b1 || rck_len_cnt==I_cfg_rck_len[15:1]+1)
        rck_2018 <= ~rck_2018;
		
//=================ICN2013=========================================================

assign clk_num_2013 = {I_cfg_rck_num[4:0],4'b0000} ;
// reg[9:0] cnt_2013;
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
	    cnt_2013 <= 10'd0;
	else if(I_display_end) //一屏显示完后
	    cnt_2013 <= 10'd0;
    else if(!(&cnt_2013)) 
	    cnt_2013 <= cnt_2013  + 1'b1;
    else 
	    cnt_2013 <= cnt_2013;

always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
	    reg_flag_2013 <= 0;
    else if((cnt_2013 >= 0)&&(cnt_2013 < (clk_num_2013 + 100))) 
	    reg_flag_2013 <= 1'b1;
    else 
	    reg_flag_2013 <= 1'b0;
// 
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
	    clk_en_2013 <= 0;
    else if((cnt_2013 > 40)&&(cnt_2013 < (clk_num_2013 + 38))) 
	    clk_en_2013 <= 1'b1;
    else 
	    clk_en_2013 <= 1'b0;
		
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
        clk_len_cnt_2013 <= 0;
    else if(clk_en_2013)
        clk_len_cnt_2013 <= clk_len_cnt_2013 + 1'b1;
    else
        clk_len_cnt_2013 <= 0;
	
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
	    B_2013 <= 1'b0;
    else if((cnt_2013==0)||(cnt_2013==12)||(cnt_2013==(clk_num_2013 + 72))) 
        B_2013 <= 1'b0;
    else if((cnt_2013 == 3)||(cnt_2013 == (clk_num_2013 + 84)))
        B_2013 <= 1'b1;
    else if(clk_len_cnt_2013 == 7)
        B_2013 <= ~B_2013;
    else 
        B_2013 <= B_2013;	

always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        A_2013 <= 0;
    else if(cnt_2013 == 20) 
        A_2013 <= 1;	 
    else if(cnt_2013 == (clk_num_2013 + 60))
        A_2013 <= 0;
    else
        A_2013 <= A_2013;	 
 

//=================================================================================

//=================SM5366P=========================================================


//prep_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        prep_cnt <= 10'd1023;
    //else if(I_scan_prep) 
    else if(I_scan_commit) 
        prep_cnt <= 10'd1;
    else if(prep_cnt<1023)
        prep_cnt <= prep_cnt + 1'b1;	
		  
assign clk_num_5366 = I_cfg_rck_num + 10'd10 ;//时钟个数

reg [6:0] display_end_cnt;
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
        display_end_cnt <= 'hff;
    else if(I_display_end)   
        display_end_cnt <= 'd0;    
    else if(display_end_cnt == 7'hff)  
        display_end_cnt <= 'hff;
    else 
        display_end_cnt <= display_end_cnt + 'd1;

always@(posedge I_sclk or negedge I_rst_n) //sm5366p寄存器配置标志
    if(!I_rst_n) 
	    reg_flag_5366 <= 1'b0;
    //else if(I_display_end) //一屏显示完后
    else if(display_end_cnt == 'd100) //一屏显示完后
	    reg_flag_5366 <= 1'b1;
    else if((cyc_cnt_5366 == 9) && (num_cnt_5366 == clk_num_5366))
	    reg_flag_5366 <= 1'b0;

//clk 时钟周期大小计数		
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
	    cyc_cnt_5366 <= 4'd0;
    else if(reg_flag_5366)  begin
        if(cyc_cnt_5366 == 9) 
            cyc_cnt_5366 <= 4'd0;	
        else
	        cyc_cnt_5366 <= cyc_cnt_5366  + 1'b1;
    end
    else 
	    cyc_cnt_5366 <= 4'd0;

//clk 时钟个数计数	
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n) 
	     num_cnt_5366 <= 4'd0;
    else if((cyc_cnt_5366 == 9) && (num_cnt_5366 == clk_num_5366))
	     num_cnt_5366 <= 4'd0;	
    else if(cyc_cnt_5366 == 9) 
        num_cnt_5366 <= num_cnt_5366  + 1'b1;
    else if(!reg_flag_5366)
        num_cnt_5366 <= 10'd0;

//BK_5366		
always@(posedge I_sclk or negedge I_rst_n) //
    if(!I_rst_n) 
	    BK_5366 <= 1'b0;
    else if((cyc_cnt_5366 == 7) && ((num_cnt_5366 == 0) || (num_cnt_5366 == clk_num_5366-6))) //
	    BK_5366 <= 1'b1;
    else if((cyc_cnt_5366 == 7) && ((num_cnt_5366 == 8) || (num_cnt_5366 == clk_num_5366-2)))
	    BK_5366 <= 1'b0;
    else if(!reg_flag_5366)
	    BK_5366 <= 1'b0;

//时钟使能信号		
always@(posedge I_sclk or negedge I_rst_n) 
    if(!I_rst_n) 
	    clk_en_5366 <= 1'b0;
	else if((cyc_cnt_5366 == 9) && (num_cnt_5366 == 0))
	    clk_en_5366 <= 1'b1;
    else if((cyc_cnt_5366 == 9) && (num_cnt_5366 == clk_num_5366-2))
	    clk_en_5366 <= 1'b0;
	else if(!reg_flag_5366)
	    clk_en_5366 <= 1'b0;	
		
always@(posedge I_sclk or negedge I_rst_n)//clk 时钟周期
    if(!I_rst_n) 
	    CLK_5366 <= 1'b0;
    else if(clk_en_5366)  begin //寄存器
	    if(cyc_cnt_5366 == 0) 
            CLK_5366 <= 1'b1;	
        else if(cyc_cnt_5366 == 5) 
	        CLK_5366 <= 1'b0;
	end
	else if(prep_cnt==10'd5) //行信号
	    CLK_5366 <= 1'b1;
	else if(prep_cnt=='d86/* cfg_decode_param1+40 */)
        CLK_5366 <= 1'b0;

always@(posedge I_sclk or negedge I_rst_n) //
    if(!I_rst_n) 
	    data_en_5366 <= 1'b0;
	else if((cyc_cnt_5366 == 7) && (num_cnt_5366 == 8)) 
	    data_en_5366 <= 1'b1;
    else if((cyc_cnt_5366 == 7) && (num_cnt_5366 == clk_num_5366-2))
	    data_en_5366 <= 1'b0;
	else if(!reg_flag_5366)
	    data_en_5366 <= 1'b0;

always@(posedge I_sclk or negedge I_rst_n) //
    if(!I_rst_n) 
	    data_5366 <= 6'd0;
	else if(data_en_5366 && (cyc_cnt_5366 == 7))
	    data_5366 <= {data_5366[4:0],data_5366[5]};
	else if(!reg_flag_5366)
	    data_5366 <= I_cfg_decode_param2 ;//6'b110010;
		
always@(posedge I_sclk or negedge I_rst_n) //
    if(!I_rst_n) 
        DIN_5366 <= 1'd0;
    else if(reg_flag_5366)  begin //寄存器值
        if(data_en_5366)
	        DIN_5366 <= data_5366[5];
        else
            DIN_5366 <= 1'b0;
    end
    //else if(prep_cnt==1 && scan_out==0)//第一扫
    else if(prep_cnt==1 && scan_result==0)//第一扫
        DIN_5366 <= 1'b1;
    else if(prep_cnt=='d20/* cfg_decode_param1 */)
        DIN_5366 <= 1'b0;

//=================================================================================

//assign pad_param0 = cfg_decode_param0 + {~I_cfg_scan_max[2:0], 3'd7};
//assign pad_param1 = cfg_decode_param1 + {~I_cfg_scan_max[2:0], 3'd7};
  assign pad_param0 = cfg_decode_param0 + {~I_cfg_scan_max[2:0], 4'd15};
  assign pad_param1 = cfg_decode_param1 + {~I_cfg_scan_max[2:0], 4'd15};
  assign pad_param2 = {~I_cfg_scan_max[2:0], 4'd15};

//bk_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        bk_5266 <= 'b0;
    else if(I_scan_commit)
        bk_5266 <= 1'b1;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param1       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param1))
        bk_5266 <= 'b0;

//din_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        din_5266 <= 'b0;
    else if(pad_flag_5266)
        begin
           if(pad_cnt_5266==1)
         //   if(commit_cnt==pad_param2)
                din_5266 <= 1'b1;
            else if(commit_cnt==pad_param1)
                din_5266 <= 'b0;
        end
    else
        begin
            if(commit_cnt==1 && scan_result[2:0]==0)
                din_5266 <= 1'b1;
            else if(commit_cnt==cfg_decode_param1)
                din_5266 <= 'b0;
        end

//dck_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dck_5266 <= 'b0;
  //else if(pad_cnt_5266[2:0]==7)
  else if(pad_cnt_5266[3:0]==15)
        dck_5266 <= 1'b1;
  //else if(pad_cnt_5266[2:0]==3)
  else if(pad_cnt_5266[3:0]==7)
        dck_5266 <= 1'b0;
    else if(pad_flag_5266)
        begin
            if(commit_cnt==pad_param0)
                dck_5266 <= 1'b1;
            else if(commit_cnt==pad_param1)
                dck_5266 <= 'b0;
        end
    else
        begin
            if(commit_cnt==cfg_decode_param0)
                dck_5266 <= 1'b1;
            else if(commit_cnt==cfg_decode_param1)
                dck_5266 <= 'b0;
        end

//d_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        d_5266 <= 'b0;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param0       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param0))
        d_5266 <= scan_result[3];

//e_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        e_5266 <= 'b0;
    else if(  ( pad_flag_5266 && commit_cnt==pad_param0       )
            ||(!pad_flag_5266 && commit_cnt==cfg_decode_param0))
        e_5266 <= scan_result[4];

//pad_flag_5266
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        pad_flag_5266 <= 'b0;
    else if(I_cfg_scan_max<=7 || I_cfg_scan_max[2:0]==7)
        pad_flag_5266 <= 'b0;
    else if(I_scan_commit)
    begin
        if(scan_result==0)
            pad_flag_5266 <= 1'b1;
        else
            pad_flag_5266 <= 'b0;
    end

//pad_cnt_5266[6:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        pad_cnt_5266 <= 'b0;
    else if(pad_flag_5266 && commit_cnt==cfg_decode_param0-2)
      //pad_cnt_5266 <= {~I_cfg_scan_max[2:0], 3'd0};
        pad_cnt_5266 <= {~I_cfg_scan_max[2:0], 4'd0};
    else if(pad_cnt_5266 != 0)
        pad_cnt_5266 <= pad_cnt_5266 - 1'b1;
//****************************************************************
assign O_deghost_ctrl = ctrl_en;

//dly_en
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dly_en <= 'b0;
    else if(I_scan_commit)
        dly_en <= 1'b1;
    else if(dly_cnt==I_cfg_deghost_ctrl_dly[9:0])
        dly_en <= 'b0;

//dly_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        dly_cnt <= 'b0;
    else if(dly_en==1)
        dly_cnt <= dly_cnt + 1'b1;
    else
        dly_cnt <= 'b0;

//ctrl_en
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        ctrl_en <= 'b0;
    else if(dly_en==1 && dly_cnt==I_cfg_deghost_ctrl_dly[9:0])
        ctrl_en <= 1'b1;
    else if(ctrl_cnt==I_cfg_deghost_ctrl_len[9:0])
        ctrl_en <= 'b0;

//ctrl_cnt[9:0]
always@(posedge I_sclk or negedge I_rst_n)
    if(!I_rst_n)
        ctrl_cnt <= 'b0;
    else if(ctrl_en==1)
        ctrl_cnt <= ctrl_cnt + 1'b1;
    else
        ctrl_cnt <= 'b0;

//****************************************************************
endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
